package com.jml.jdk8.stream;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Collector的三个泛型
 * 第一个参数是集合中元素的类型
 * 第二个参数是临时创建的容器
 * 第三个参数是最终返回的容器
 */
public class C自定义Collector<T> implements Collector<T, Set<T>, Set<T>> {
    /**
     * 一个是提供新的容器
     */
    @Override
    public Supplier<Set<T>> supplier() {
        System.out.println("supplier invoked");
        return () -> new HashSet<T>();
        // return HashSet::new;

    }

    /**
     * 一个是不断往结果容器中追加内容，对容器进行操作(可以是任意操作)
     */
    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        System.out.println("accumulator invoked");
        //return (HashSet<T> set ,T t) ->set.add(t);
        return (Set<T> set, T t) -> set.add(t);
        //return Set<T>::add;
        //不能用HashSet<T>::add;也不能用(HashSet<T> set ,T t) ->set.add(t);
        //因为接口定义的中间容器是Set<T>,
        //               supplier返回值是HashSet也可以是TreeSet，
        // 这里如果用具体的set进行add操作，类型可能会和supplier中定义的set不一致，
        // 所以只能用原生的set进行add，永远会和supplier中定义的set一致
        // return HashSet<T>::add;
    }

    /**
     * 一个是将并行流的结果容器合并到一起
     */
    @Override
    public BinaryOperator<Set<T>> combiner() {
        System.out.println("combiner invoked");
        return (set1, set2) -> {
            set1.addAll(set2);
            return set1;
        };
    }

    /**
     * 一个是将累计结果类型转化为另一个结果类型
     */
    @Override
    public Function<Set<T>, Set<T>> finisher() {
        System.out.println("finisher invoked");
//        return (set) -> set;
//        return Function.identity();
        return (set) -> (HashSet) set;
    }

    //返回的是一个Set的集合。这个集合表明当前收集器诸多的特性
    @Override
    public Set<Characteristics> characteristics() {
        System.out.println("characteristics invoked");
        //unmodifiableSet是不能修改的集合
        //如果设定为IDENTITY_FINISH，就不会调用finisher方法，
        //                               那么finisher中的方法可以写抛异常
        // 如果设定为IDENTITY_FINISH就会直接就返回中间容器，
        //                           把中间容器强转为最终的返回类型然后返回
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH,
                Characteristics.UNORDERED));
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("Hello", "world", "welcome", "Hello");
        C自定义Collector myCollector = new C自定义Collector();
        Set<String> set = list.stream().collect(new C自定义Collector<>());
        System.out.println(set);
    }
}
